import java.awt.Color;
import java.awt.FileDialog;
import java.awt.Font;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.io.*;
import java.nio.CharBuffer;
import java.util.Stack;

import javax.swing.BorderFactory;
import javax.swing.Box;
import javax.swing.JButton;
import javax.swing.JFileChooser;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JOptionPane;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JTextArea;
import javax.swing.JTextField;
import javax.swing.border.Border;
import javax.swing.filechooser.FileNameExtensionFilter;

/**
 * @author Huhao
 * &#064;date  2024/11/20
 */

public class NFA_DFA_MFA implements ActionListener {
    JTextField text1;
    private JFrame frame;
    static JTextArea area1;
    static JTextArea area2;
    static JTextArea area3;
    private JButton run,exit,get1,born1,save1,get2,born2,save2,born3;
    static JTextField label1_s,label1_e,label2_s,label2_e,label3_s,label3_e;
    Box box0;
    public NFA_DFA_MFA(){
        frame = new JFrame();
        frame.setLayout(null);
        frame.setTitle("NFA-DFA-MFA");
        init();
        frame.setBounds(200,20,1020,680);
        frame.setVisible(true);
        frame.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
    }
    public void init(){
        //正规式的输入
        JPanel panel=new JPanel();
        text1=new JTextField(30);
        text1.setFont(new Font("宋体", Font.BOLD, 25));
        JLabel label=new JLabel("请输入正规式:");
        run=new JButton("验证正规式");
        exit=new JButton("退出");
        run.addActionListener(this);
        exit.addActionListener(this);
        panel.add(label);
        panel.add(text1);
        panel.add(run);
        panel.add(exit);
        panel.setBounds(10, 10, 1000, 40);
        frame.add(panel);

        box0=Box.createHorizontalBox();
        box0.setBounds(10, 50, 1000, 600);

        frame.add(box0);

        JPanel panel1=new JPanel();
        panel1.setLayout(null);

        JLabel label1=new JLabel("正规式-NFA");
        JLabel label1_a=new JLabel("起始状态");
        JLabel label1_b=new JLabel("接收符号");
        JLabel label1_c=new JLabel("到达状态");
        label1.setFont(new Font("宋体",Font.BOLD,18));
        label1_a.setFont(new Font("宋体",Font.BOLD,18));
        label1_b.setFont(new Font("宋体",Font.BOLD,18));
        label1_c.setFont(new Font("宋体",Font.BOLD,18));

        JPanel panel1_title=new JPanel();
        panel1_title.add(label1_a);
        panel1_title.add(new JLabel("   "));
        panel1_title.add(label1_b);
        panel1_title.add(new JLabel("   "));
        panel1_title.add(label1_c);

        area1=new JTextArea(20,90);

        label1_s=new JTextField("开始状态集：");
        label1_e=new JTextField("终结状态集：");
        label1_s.setEditable(false);
        label1_e.setEditable(false);
        get1=new JButton("读入NFA文件");
        born1=new JButton("生成NFA");
        save1=new JButton("保存NFA文件");
        label1_s.setFont(new Font("宋体",Font.BOLD,18));
        label1_e.setFont(new Font("宋体",Font.BOLD,18));

        Box box1=Box.createHorizontalBox();
        box1.add(get1);
        box1.add(born1);
        box1.add(save1);

        label1.setBounds(5, 0, 300, 50);
        panel1_title.setBounds(5, 50, 300, 30);
        panel1.add(label1);
        panel1.add(panel1_title);

        area1.setFont(new Font("宋体",Font.BOLD,32));

        JScrollPane scrollPane =new JScrollPane();
        scrollPane .setViewportView(area1 );
        scrollPane .setHorizontalScrollBarPolicy(JScrollPane.HORIZONTAL_SCROLLBAR_NEVER);
        scrollPane .setVerticalScrollBarPolicy(JScrollPane.VERTICAL_SCROLLBAR_AS_NEEDED);
        scrollPane.setBounds(5, 92, 300, 350);
        panel1.add(scrollPane);
        label1_s.setBounds(5, 445, 300, 30);
        panel1.add(label1_s);
        label1_e.setBounds(5, 475, 300, 30);
        panel1.add(label1_e);
        box1.setBounds(5, 500, 300, 90);
        panel1.add(box1);
        box0.add(panel1);


        JPanel panel2=new JPanel();
        panel2.setLayout(null);
        JLabel label2=new JLabel("NFA-DFA");
        JLabel label2_a=new JLabel("起始状态");
        JLabel label2_b=new JLabel("接收符号");
        JLabel label2_c=new JLabel("到达状态");
        label2.setFont(new Font("宋体",Font.BOLD,18));
        label2_a.setFont(new Font("宋体",Font.BOLD,18));
        label2_b.setFont(new Font("宋体",Font.BOLD,18));
        label2_c.setFont(new Font("宋体",Font.BOLD,18));

        JPanel panel2_title=new JPanel();
        panel2_title.add(label2_a);
        panel2_title.add(new JLabel("   "));
        panel2_title.add(label2_b);
        panel2_title.add(new JLabel("   "));
        panel2_title.add(label2_c);

        area2=new JTextArea(20,90);
        area2 .setLineWrap(true);
        label2_s=new JTextField("开始状态集：");
        label2_e=new JTextField("终结状态集：");
        label2_s.setEditable(false);
        label2_e.setEditable(false);
        label2_s.setFont(new Font("宋体",Font.BOLD,18));
        label2_e.setFont(new Font("宋体",Font.BOLD,18));

        Box box2=Box.createHorizontalBox();
        get2=new JButton("读入DFA文件");
        born2=new JButton("生成DFA");
        save2=new JButton("保存DFA文件");
        box2.add(get2);
        box2.add(born2);
        box2.add(save2);
        label2.setBounds(5, 0, 300, 50);
        panel2.add(label2);
        panel2_title.setBounds(5, 50, 300, 30);
        panel2.add(panel2_title);
        area2.setFont(new Font("宋体",Font.BOLD,32));
        JScrollPane scrollPane2 =new JScrollPane();
        scrollPane2 .setViewportView(area2 );
        scrollPane2 .setHorizontalScrollBarPolicy(JScrollPane.HORIZONTAL_SCROLLBAR_NEVER);
        scrollPane2 .setVerticalScrollBarPolicy(JScrollPane.VERTICAL_SCROLLBAR_AS_NEEDED);
        scrollPane2.setBounds(5, 92, 300, 350);
        panel2.add(scrollPane2);
        label2_s.setBounds(5, 445, 300, 30);
        panel2.add(label2_s);
        label2_e.setBounds(5, 475, 300, 30);
        panel2.add(label2_e);
        box2.setBounds(5, 500, 300, 90);
        panel2.add(box2);
        box0.add(panel2);

        JPanel panel3=new JPanel();
        panel3.setLayout(null);
        JLabel label3=new JLabel("DFA-MFA");
        label3.setFont(new Font("宋体",Font.BOLD,18));
        JPanel panel3_title=new JPanel();

        JLabel label3_a=new JLabel("起始状态");
        JLabel label3_b=new JLabel("接收符号");
        JLabel label3_c=new JLabel("到达状态");
        label3_a.setFont(new Font("宋体",Font.BOLD,18));
        label3_b.setFont(new Font("宋体",Font.BOLD,18));
        label3_c.setFont(new Font("宋体",Font.BOLD,18));
        panel3_title.add(label3_a);
        panel3_title.add(new JLabel("   "));
        panel3_title.add(label3_b);
        panel3_title.add(new JLabel("   "));
        panel3_title.add(label3_c);

        area3=new JTextArea(20,90);
        area3 .setLineWrap(true);
        label3_s=new JTextField("开始状态集：");
        label3_e=new JTextField("终结状态集：");
        label3_s.setEditable(false);
        label3_e.setEditable(false);
        label3_s.setFont(new Font("宋体",Font.BOLD,18));
        label3_e.setFont(new Font("宋体",Font.BOLD,18));


        Box box3=Box.createHorizontalBox();
        born3=new JButton("生成MFA");
        box3.add(born3);
        label3.setBounds(5, 0, 300, 50);
        panel3.add(label3);
        panel3_title.setBounds(5, 50, 300, 30);
        panel3.add(panel3_title);
        area3.setFont(new Font("宋体",Font.BOLD,32));
        JScrollPane scrollPane3 =new JScrollPane();
        scrollPane3 .setViewportView(area3 );
        scrollPane3 .setHorizontalScrollBarPolicy(JScrollPane.HORIZONTAL_SCROLLBAR_NEVER);
        scrollPane3 .setVerticalScrollBarPolicy(JScrollPane.VERTICAL_SCROLLBAR_AS_NEEDED);
        scrollPane3.setBounds(5, 92, 300, 350);
        panel3.add(scrollPane3);
        label3_s.setBounds(5, 445, 300, 30);
        panel3.add(label3_s);
        label3_e.setBounds(5, 475, 300, 30);
        panel3.add(label3_e);
        box3.setBounds(5, 500, 300, 90);
        panel3.add(box3);
        box0.add(panel3);

        get1.addActionListener(this);
        born1.addActionListener(this);
        save1.addActionListener(this);

        get2.addActionListener(this);
        born2.addActionListener(this);
        save2.addActionListener(this);

        born3.addActionListener(this);

    }

    @Override
    public void actionPerformed(ActionEvent e) {
        Object o = e.getSource();
        if(o==run){
            String a=text1.getText();
            boolean result = IsZhenggui(a);
            if(result){
                JOptionPane.showMessageDialog(null,"所输入为正规式",  "正确",JOptionPane.PLAIN_MESSAGE);
            }
            else {
                JOptionPane.showMessageDialog(null, "所输入为非法正规式","错误",JOptionPane.ERROR_MESSAGE);
            }

        }
        if(o==exit){
            frame.setVisible(false);
        }
        if(o==get1){
            File getPath;
            JFileChooser jf=new JFileChooser("../");
            FileNameExtensionFilter filter = new FileNameExtensionFilter("文本文档(*.txt)", "txt");
            jf.setFileFilter(filter);
            int value=jf.showOpenDialog(frame);
            if(value==JFileChooser.APPROVE_OPTION){
                getPath=jf.getSelectedFile();
                File fp=getPath;
                File fileflag=fp;
                BufferedReader reader = null;
                String tempString = null;
                String sum="";
                int line =1;
                try {
                    reader = new BufferedReader(new FileReader(fp));
                    while ((tempString = reader.readLine()) != null) {
                        if(sum.equals(""))
                            sum=sum+tempString;
                        else
                            sum=sum+"\n"+tempString;
                        line ++ ;
                    }

                    this.area1.setText(sum);
                    reader.close();
                } catch (FileNotFoundException e1) {

                } catch (IOException e2) {

                }finally{
                    if(reader != null){
                        try {
                            reader.close();
                        } catch (IOException e3) {

                        }
                    }
                }
            }else{
            }
        }
        if(o==born1){
            String a=text1.getText().trim();
            new ToNFA(a);
        }
        if(o==save1){String path;
            String content = area1.getText();
            JFileChooser chooser = new JFileChooser();
            FileNameExtensionFilter filter = new FileNameExtensionFilter("文本文件(*.txt)", "txt");
            chooser.setFileFilter(filter);
            int res =chooser.showSaveDialog(null);
            if(res == JFileChooser.APPROVE_OPTION){
                path = chooser.getSelectedFile().getAbsolutePath() + ".txt";// 获得保存路径
                try {
                    OutputStreamWriter writer = new OutputStreamWriter(new FileOutputStream(path), "UTF-8");
                    writer.write(content);
                    writer.close();
                } catch (IOException e1) {
                    e1.printStackTrace();
                }
            }
        }
        if(o==get2){
            File getPath;
            JFileChooser jf=new JFileChooser("../");
            FileNameExtensionFilter filter = new FileNameExtensionFilter("文本文档(*.txt)", "txt");
            jf.setFileFilter(filter);
            int value=jf.showOpenDialog(frame);
            if(value==JFileChooser.APPROVE_OPTION){
                getPath=jf.getSelectedFile();
                File fp=getPath;
                File fileflag=fp;
                BufferedReader reader = null;
                String tempString = null;
                String sum="";
                int line =1;
                try {
                    reader = new BufferedReader(new FileReader(fp));
                    while ((tempString = reader.readLine()) != null) {
                        sum=sum+tempString;
                        line ++ ;
                    }

                    this.area2.setText(sum);
                    reader.close();
                } catch (FileNotFoundException e1) {

                } catch (IOException e2) {

                }finally{
                    if(reader != null){
                        try {
                            reader.close();
                        } catch (IOException e3) {

                        }
                    }
                }
            }else{
            }
        }
        if(o==born2){
            String a=text1.getText().trim();
            new ToDefinedDFA(a);
        }
        if(o==save2){
            FileDialog savedia;
            File fileflag=null;
            savedia=new FileDialog(frame,"保存",FileDialog.SAVE);
            if(fileflag==null){
                savedia.setVisible(true);
                String dirPath=savedia.getDirectory();
                String fileName=savedia.getFile();
                fileName=fileName+".txt";
                if(dirPath==null||fileName==null)
                    return ;
                fileflag=new File(dirPath,fileName);
                try{
                    BufferedWriter bfwt=new BufferedWriter(new FileWriter(fileflag));
                    String t= area2.getText();
                    bfwt.write(t);
                    bfwt.close();

                }
                catch (IOException ex){
                    throw new RuntimeException();
                }
            }
        }
        if(o==born3){
            String a=text1.getText().trim();
            new ToMinimumDFA(a);
        }
    }

    private boolean IsZhenggui(String exp) {
        exp.replace (" ", "");//删除所有空白字符
        Stack bracket = new Stack();//存储括号
        if (exp == " ")
            return false;
        if (exp.charAt(0) == '(' && exp.charAt(exp.length() - 1) == ')')//表达式是括号表达式
        {
            int i;
            for (i = 0; i < exp.length(); i++)
            {
                if (exp.charAt(i) == '(')
                    bracket.push('(');
                else if (exp.charAt(i) == ')')
                    bracket.pop();
                if (bracket.stream().count() == 0)
                    break;
            }
            if (i == exp.length() - 1)
            {
                exp = exp.substring(1,exp.length()-1);
                if(exp!=null)
                    return IsZhenggui(exp);
                else
                    return true;
            }
        }
        if (exp.contains("|"))
        {
            for (int i = 0; i < exp.length(); i++)
            {
                if (exp.charAt(i) == '(')
                    bracket.push(exp.charAt(i));
                else if (exp.charAt(i) == ')')
                {
                    if (bracket.stream().count() == 0)
                        return false;
                    bracket.pop();
                }
                else if (bracket.stream().count() == 0 && exp.charAt(i) == '|')
                {
                    String left = exp.substring(0, i);
                    String right = exp.substring(i+1,exp.length());
                    return IsZhenggui(left) && IsZhenggui(right);
                }
            }
            if (bracket.stream().count() != 0)//左右括号不能完全匹配
                return false;
        }
        if (exp.length() > 0)
        {
            int i;
            for (i = 0; i < exp.length(); i++)
            {
                if (exp.charAt(i) == '(')
                    bracket.push(exp.charAt(i));
                else if (exp.charAt(i) == ')')
                {
                    if (bracket.stream().count() == 0)
                        return false;
                    bracket.pop();
                }
                if (bracket.stream().count() == 0)
                {
                    if (i < exp.length()-1 && exp.charAt(i+1) != '*')
                    {
                        String left = exp.substring(0, i + 1);
                        String right = exp.substring(i + 1);
                        return IsZhenggui(left) && IsZhenggui(right);
                    }
                }
            }
            if (bracket.stream().count() != 0)
                return false;
            if (i == exp.length())
                if (exp.contains("*"))
                {
                    for (i = 0; i < exp.length(); i++)
                    {
                        if (exp.charAt(i) == '(')
                            bracket.push(exp.charAt(i));
                        else if (exp.charAt(i) == ')')
                        {
                            if (bracket.stream().count() == 0)
                                return false;
                            bracket.pop();
                        }
                        else if (bracket.stream().count() == 0 && exp.charAt(i) == '*')
                            return IsZhenggui(exp.substring(0, exp.length() - 1));

                    }
                    if (bracket.stream().count() != 0)//左右括号不能完全匹配
                        return false;
                }
                else if (exp.length() == 1)
                    return true;
        }
        return false;
    }
}
